<!DOCTYPE html>
<!--
Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->

<link rel="import" href="/tracing/base/color.html">
<link rel="import" href="/tracing/base/math/math.html">
<link rel="import" href="/tracing/base/utils.html">

<script>
'use strict';
tr.exportTo('tr.b', function() {
  /**
   * Generate pretty colors!
   * http://basecase.org/env/on-rainbows
   * https://mycarta.wordpress.com/2012/10/06/the-rainbow-is-deadlong-live-the-rainbow-part-3/
   *
   * Set brightness = 0 to always generate black.
   * Set brightness = 2 to always generate white.
   * Set brightness = 1 to generate saturated colors.
   *
   * @constructor
   * @param {number=} opt_a alpha opacity in [0,1]
   * @param {number=} opt_brightness in [0,2]
   */
  function SinebowColorGenerator(opt_a, opt_brightness) {
    this.a_ = (opt_a === undefined) ? 1 : opt_a;
    this.brightness_ = (opt_brightness === undefined) ? 1 : opt_brightness;
    this.colorIndex_ = 0;
    this.keyToColor = {};
  }

  SinebowColorGenerator.prototype = {
    colorForKey(key) {
      if (!this.keyToColor[key]) {
        this.keyToColor[key] = this.nextColor();
      }
      return this.keyToColor[key];
    },

    nextColor() {
      const components = SinebowColorGenerator.nthColor(this.colorIndex_++);
      return tr.b.Color.fromString(SinebowColorGenerator.calculateColor(
          components[0], components[1], components[2],
          this.a_, this.brightness_));
    }
  };

  SinebowColorGenerator.PHI = (1 + Math.sqrt(5)) / 2;

  SinebowColorGenerator.sinebow = function(h) {
    h += 0.5;
    h = -h;
    let r = Math.sin(Math.PI * h);
    let g = Math.sin(Math.PI * (h + 1 / 3));
    let b = Math.sin(Math.PI * (h + 2 / 3));
    r *= r; g *= g; b *= b;
    // Roughly correct for human perception.
    // https://en.wikipedia.org/wiki/Luma_%28video%29
    // Multiply by 2 to normalize all values to 0.5.
    // (Halfway between black and white.)
    const y = 2 * (0.2989 * r + 0.5870 * g + 0.1140 * b);
    r /= y; g /= y; b /= y;
    return [256 * r, 256 * g, 256 * b];
  };

  SinebowColorGenerator.nthColor = function(n) {
    return SinebowColorGenerator.sinebow(n * this.PHI);
  };

  SinebowColorGenerator.calculateColor = function(r, g, b, a, brightness) {
    if (brightness <= 1) {
      r *= brightness;
      g *= brightness;
      b *= brightness;
    } else {
      r = tr.b.math.lerp(tr.b.math.normalize(brightness, 1, 2), r, 255);
      g = tr.b.math.lerp(tr.b.math.normalize(brightness, 1, 2), g, 255);
      b = tr.b.math.lerp(tr.b.math.normalize(brightness, 1, 2), b, 255);
    }
    r = Math.round(r);
    g = Math.round(g);
    b = Math.round(b);
    return 'rgba(' + r + ',' + g + ',' + b + ', ' + a + ')';
  };

  return {
    SinebowColorGenerator,
  };
});
</script>
